library(tidyverse)
library(ggthemes)
library(gridExtra)
library(langcog) # for multi_boot_standard
  
theme_set(theme_few())
# langcog package is installed by running
# install.packages("devtools")
# devtools::install_github("langcog/langcog")
# make a base plots
# for flipped coordinate system with prop correct on x
p1 <- ggplot() +
  geom_hline(yintercept = 1/3, lty = 2) +
  scale_y_continuous("Proportion Correct", limits = c(-0.05, 1.05)) +
  theme(axis.title.y = element_blank(), axis.ticks.y = element_blank())
p2 <- p1 + theme(axis.text.y = element_blank())

Intro

These are some preliminary visualizations of the data.

phylo <- read_csv("../data/species_data.csv") %>% 
  select(species, species_formatted, clade, clade_formatted, phylo)
mp_data <- read.csv("../data/merged_data/01_manyprimates_pilot_merged_data_v2.csv",
                    stringsAsFactors = F) %>%
  left_join(phylo, by = "species") %>%
  mutate(species = species_formatted,
         species = reorder(species, phylo),
         clade = clade_formatted,
         clade = fct_relevel(clade, "Lemur", "New World monkey", "Old World monkey", "Ape"),
         delay = factor(delay))

Overview by species

First an overview of the data, plotted by species and delay. Small, transparent dots represent aggregated data for each individual by delay. Open dots are the group mean for that delay. Error bars are 95% confidence intervals. Text labels are the sample size.

plot_individual <- mp_data %>%
  group_by(phylo, clade, species, delay, subject_site) %>%
  summarise(correct = mean(correct),
            nr_trials = max(trial))
plot_group <- plot_individual %>%
   multi_boot_standard(col = "correct")
# get sample sizes (for use in plots)
ns <- mp_data %>%
  group_by(clade, species) %>%
  mutate(n = n_distinct(subject_site)) %>%
  group_by(clade, species, site, n) %>%
  summarise(n_by_site = n_distinct(subject_site))
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = plot_individual, aes(size = nr_trials), width = .1, height = .015, alpha = .15) +
  geom_point(data = plot_group, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
  geom_linerange(data = plot_group, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
  # geom_text(data = ns, aes(label = n), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(species ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180, hjust = 0)) +
  scale_size_area("Number of Trials", max_size = 3, breaks = c(12, 24, 36)) +
  scale_colour_solarized("Delay", breaks = c("short", "medium", "long")) +
  coord_flip(ylim = 0:1)

ggsave("../graphs/02_01_overview.png", width = 4, height = 4.5, scale = 2)
ggsave("../graphs/Fig2.tiff", width = 4, height = 4.5, scale = 2, type = "cairo", compression = "lzw")

Overview by species across delays

plot_individual2 <- plot_individual %>%
  group_by(clade, species, subject_site) %>%
  summarise(correct = mean(correct))
plot_group2 <- plot_individual2 %>%
   multi_boot_standard(col = "correct")
p1 + aes(x = fct_rev(species), y = correct, col = clade) +
  geom_jitter(data = plot_individual2, width = .1, height = .015, alpha = .15, size = 3) +
  geom_point(data = plot_group2, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
  geom_linerange(data = plot_group2, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
  geom_text(data = ns, aes(label = n), y = -.05, col = "black", size = 3) +
  facet_grid(clade ~ ., scales = "free_y", space = "free_y") +
  theme(strip.text.y = element_blank()) +
  scale_colour_solarized() +
  coord_flip()

ggsave("../graphs/02_02_overview_across_delays.png", width = 4, height = 1.8, scale = 2)

Plots by site

Here we select the species for which we have data from multiple sites. This is a very preliminary way of checking whether there is a lot of variation between sites. Plotting conventions are the same as above.

First we check for which species we have data from more than one site:

mp_data %>%
  group_by(species) %>%
  summarise(sites = n_distinct(site)) %>%
  arrange(desc(sites)) %>%
  knitr::kable()
species sites
Chimpanzee 5
Ring-tailed lemur 2
Brown capuchin monkey 2
Bonobo 2
Gorilla 2
Black-and-white ruffed lemur 1
Black-faced spider monkey 1
Squirrel monkey 1
Rhesus macaque 1
Long-tailed macaque 1
Barbary macaque 1
Orangutan 1

Chimpanzees

chimp_plot_individual <- mp_data %>%
  filter(species == "Chimpanzee") %>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
chimp_plot_group <- chimp_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = chimp_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = chimp_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == "Chimpanzee"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(site ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c("short", "medium", "long")) +
  ggtitle("Chimpanzees") +
  coord_flip()

# ggsave("../graphs/02_03_chimp_by_site.png", width = 4, height = 2.5, scale = 2, type = "cairo", compression = "lzw")
ggsave("../graphs/02_03_chimp_by_site.png", width = 4, height = 2.5, scale = 2)

Ring-tailed lemurs

rtlemur_plot_individual <- mp_data %>%
  filter(species == "Ring-tailed lemur") %>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
rtlemur_plot_group <- rtlemur_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = rtlemur_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = rtlemur_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == "Ring-tailed lemur"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(site ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c("short", "medium", "long")) +
  ggtitle("Ring-tailed lemurs") +
  coord_flip()

ggsave("../graphs/02_04_rtlemur_by_site.png", width = 4, height = 1.2, scale = 2)

Brown Capuchins

cap_plot_individual <- mp_data %>%
  filter(species == "Brown capuchin monkey") %>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
cap_plot_group <- cap_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = cap_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = cap_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == "Brown capuchin monkey"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(site ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c("short", "medium", "long")) +
  ggtitle("Capuchin Monkeys") +
  coord_flip()

ggsave("../graphs/02_05_capuchin_by_site.png", width = 4, height = 1.2, scale = 2)

Bonobos

bon_plot_individual <- mp_data %>%
  filter(species == "Bonobo") %>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
bon_plot_group <- bon_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = bon_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = bon_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == "Bonobo"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(site ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c("short", "medium", "long")) +
  ggtitle("Bonobos") +
  coord_flip()

ggsave("../graphs/02_06_bonobo_by_site.png", width = 4, height = 1.2, scale = 2)

Gorilla

gor_plot_individual <- mp_data %>%
  filter(species == "Gorilla") %>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
gor_plot_group <- gor_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = gor_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = gor_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == "Gorilla"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(site ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c("short", "medium", "long")) +
  ggtitle("Gorillas") +
  coord_flip()

ggsave("../graphs/02_07_gorilla_by_site.png", width = 4, height = 1.2, scale = 2)

Task-experience

Here we split each species by task experience. Check if we have species with sufficient memebers having different levels of task experience.

mp_data %>%
  group_by(species) %>%
  mutate(lvls_task_exp = n_distinct(task_experience)) %>%
  filter(lvls_task_exp > 1) %>%
  group_by(species, task_experience) %>%
  summarise(n = n_distinct(subject_site)) %>%
  knitr::kable()
species task_experience n
Chimpanzee no 19
Chimpanzee yes 32
Bonobo no 6
Bonobo yes 5
# get sample sizes (for use in plots)
ns_task_exp <- mp_data %>%
  group_by(clade, species) %>%
  mutate(n = n_distinct(task_experience)) %>%
  group_by(clade, species, task_experience, n) %>%
  summarise(n_by_site = n_distinct(subject_site))

So far, this only applies to chimps and bonobos. However, task experience co-varies with site.

chimp_task_plot_individual <- mp_data %>%
  filter(species == "Chimpanzee") %>%
  group_by(site, task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct))
chimp_task_plot_group <- mp_data %>%
  filter(species == "Chimpanzee") %>%
  group_by(task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct)) %>%
  multi_boot_standard(col = "correct")
p_taskexp_chimp <- p2 + aes(x = delay, y = correct) +
  geom_jitter(data = chimp_task_plot_individual, aes(col = site), width = .3, height = .015, alpha = .5, size = 3) +
  geom_pointrange(data = chimp_task_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper, shape = delay), size = .8, stroke = 1.5) +
  geom_text(data = filter(ns_task_exp, species == "Chimpanzee"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(task_experience ~ ., switch = "y") +
  theme(legend.box = "horizontal", strip.text.y = element_text(angle = 180)) +
  scale_shape_manual(values = c(1, 2, 5), breaks = c("short", "medium", "long")) +
  scale_colour_solarized() +
  ggtitle("Chimpanzees") +
  coord_flip()
bonobo_task_plot_individual <- mp_data %>%
  filter(species == "Bonobo") %>%
  group_by(site, task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct))
bonobo_task_plot_group <- mp_data %>%
  filter(species == "Bonobo") %>%
  group_by(task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct)) %>%
  multi_boot_standard(col = "correct")
p_taskexp_bon <- p2 + aes(x = delay, y = correct) +
  geom_jitter(data = bonobo_task_plot_individual, aes(col = site), width = .3, height = .015, alpha = .5, size = 3) +
  geom_pointrange(data = bonobo_task_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper, shape = delay), size = .8, stroke = 1.5) +
  geom_text(data = filter(ns_task_exp, species == "Bbonobo"), aes(label = n_by_site), y = -.05, x = 2, col = "black", size = 3) +
  facet_grid(task_experience ~ ., switch = "y") +
  theme(legend.box = "horizontal", strip.text.y = element_text(angle = 180)) +
  scale_shape_manual(values = c(1, 2, 5), breaks = c("short", "medium", "long")) +
  scale_colour_solarized() +
  ggtitle("Bonobos") +
  coord_flip()
grid.arrange(p_taskexp_chimp, p_taskexp_bon, ncol = 1)

grob <- arrangeGrob(p_taskexp_chimp, p_taskexp_bon, ncol = 1)
ggsave("../graphs/02_08_task_experience.png", grob, width = 4, height = 3, scale = 2)

Age

Here we plot age against correct choice separate for each delay and species. Regression line is smoothed delayal mean.

plot_age <- mp_data %>%
  mutate(delay = fct_rev(delay)) %>%
  group_by(subject_site, norm_age, clade, species, delay) %>%
  summarise(correct = mean(correct))
ggplot(plot_age, aes(x = norm_age, y = correct)) +
  geom_jitter(aes(col = clade), width = .05, height = .05, alpha = .5, size = 2.5) +
  geom_smooth(method = "lm", col = "black") +
  # geom_vline(xintercept = 0, lty = 2) +
  geom_hline(yintercept = 1/3, lty = 2) +
  facet_grid(~ delay) +
  labs(x = "Normed Age (relative to species longevity)", y = "Proportion Correct") +
  scale_color_solarized("Clade") +
  ylim(c(-.05, 1.05))

ggsave("../graphs/02_09_age_by_delay.png", width = 4, height = 1.3, scale = 2)
ggsave("../graphs/Fig4.tiff", width = 4, height = 1.3, scale = 2, type = "cairo", compression = "lzw")
ggplot(plot_age, aes(x = norm_age, y = correct)) +
  geom_jitter(aes(fill = species), width = .05, height = .05, alpha = .5, size = 2.5, shape = 21, stroke = 0) +
  geom_smooth(aes(col = delay), method = "lm", show.legend = F) +
  geom_vline(xintercept = 0, lty = 2) +
  geom_hline(yintercept = 1/3, lty = 2) +
  facet_grid(delay ~ clade, scales = "free_x") +
  labs(x = "Normed Age (relative to species longevity)", y = "Proportion Correct") +
  theme(legend.position = "bottom") +
  scale_color_manual(values = rev(solarized_palette(3))) +
  ylim(c(-.05, 1.05))

ggsave("../graphs/02_10_age_by_delay_species.png", width = 4, height = 3.4, scale = 2)

Cup distance

(sig. effect in preliminary model)

plot_cup <- mp_data %>%
   group_by(subject_site, cup_distance, clade, species, delay) %>%
   summarise(correct = mean(correct))
cp <- ggplot(plot_cup, aes(x = cup_distance, y = correct)) +
  geom_jitter(aes(col = clade), width = .5, height = .15, alpha = .5, size = 2) +
  geom_smooth(method = "lm", col = "black") +
  labs(x = "Cup Distance in cm", y = "Proportion Correct") +
  geom_hline(yintercept = 1/3, lty = 2) +
  scale_color_solarized("Clade") +
  ylim(c(-.05, 1.05))
cp + theme(plot.margin = unit(c(.5, 5, .5, .5), "cm"))

ggsave("../graphs/02_11_cup_distance.png", cp, width = 3, height = 2, scale = 2)
LS0tCnRpdGxlOiAiTWFueVByaW1hdGVzIHBsb3RzIgphdXRob3I6ICJNYW51ZWwgQm9obiIKZGF0ZTogIk9jdCAzMSAyMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY3NzOiBzdHlsZS5jc3MKICAgIHRoZW1lOiBwYXBlcgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShsYW5nY29nKSAjIGZvciBtdWx0aV9ib290X3N0YW5kYXJkCiAgCnRoZW1lX3NldCh0aGVtZV9mZXcoKSkKCiMgbGFuZ2NvZyBwYWNrYWdlIGlzIGluc3RhbGxlZCBieSBydW5uaW5nCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibGFuZ2NvZy9sYW5nY29nIikKYGBgCgpgYGB7cn0KIyBtYWtlIGEgYmFzZSBwbG90cwojIGZvciBmbGlwcGVkIGNvb3JkaW5hdGUgc3lzdGVtIHdpdGggcHJvcCBjb3JyZWN0IG9uIHgKcDEgPC0gZ2dwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEvMywgbHR5ID0gMikgKwogIHNjYWxlX3lfY29udGludW91cygiUHJvcG9ydGlvbiBDb3JyZWN0IiwgbGltaXRzID0gYygtMC4wNSwgMS4wNSkpICsKICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkKCnAyIDwtIHAxICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyBJbnRybwoKVGhlc2UgYXJlIHNvbWUgcHJlbGltaW5hcnkgdmlzdWFsaXphdGlvbnMgb2YgdGhlIGRhdGEuCgpgYGB7ciBsb2FkaW5nIGRhdGEsIG1lc3NhZ2U9RkFMU0V9CnBoeWxvIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3NwZWNpZXNfZGF0YS5jc3YiKSAlPiUgCiAgc2VsZWN0KHNwZWNpZXMsIHNwZWNpZXNfZm9ybWF0dGVkLCBjbGFkZSwgY2xhZGVfZm9ybWF0dGVkLCBwaHlsbykKCm1wX2RhdGEgPC0gcmVhZC5jc3YoIi4uL2RhdGEvbWVyZ2VkX2RhdGEvMDFfbWFueXByaW1hdGVzX3BpbG90X21lcmdlZF9kYXRhX3YyLmNzdiIsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpICU+JQogIGxlZnRfam9pbihwaHlsbywgYnkgPSAic3BlY2llcyIpICU+JQogIG11dGF0ZShzcGVjaWVzID0gc3BlY2llc19mb3JtYXR0ZWQsCiAgICAgICAgIHNwZWNpZXMgPSByZW9yZGVyKHNwZWNpZXMsIHBoeWxvKSwKICAgICAgICAgY2xhZGUgPSBjbGFkZV9mb3JtYXR0ZWQsCiAgICAgICAgIGNsYWRlID0gZmN0X3JlbGV2ZWwoY2xhZGUsICJMZW11ciIsICJOZXcgV29ybGQgbW9ua2V5IiwgIk9sZCBXb3JsZCBtb25rZXkiLCAiQXBlIiksCiAgICAgICAgIGRlbGF5ID0gZmFjdG9yKGRlbGF5KSkKYGBgCgojIE92ZXJ2aWV3IGJ5IHNwZWNpZXMKCkZpcnN0IGFuIG92ZXJ2aWV3IG9mIHRoZSBkYXRhLCBwbG90dGVkIGJ5IHNwZWNpZXMgYW5kIGRlbGF5LiBTbWFsbCwgdHJhbnNwYXJlbnQgZG90cyByZXByZXNlbnQgYWdncmVnYXRlZCBkYXRhIGZvciBlYWNoIGluZGl2aWR1YWwgYnkgZGVsYXkuIE9wZW4gZG90cyBhcmUgdGhlIGdyb3VwIG1lYW4gZm9yIHRoYXQgZGVsYXkuIEVycm9yIGJhcnMgYXJlIDk1JSBjb25maWRlbmNlIGludGVydmFscy4gVGV4dCBsYWJlbHMgYXJlIHRoZSBzYW1wbGUgc2l6ZS4KCmBgYHtyIG92ZXJ2aWV3IGJ5IHNwZWNpZXMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGdyb3VwX2J5KHBoeWxvLCBjbGFkZSwgc3BlY2llcywgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpLAogICAgICAgICAgICBucl90cmlhbHMgPSBtYXgodHJpYWwpKQoKcGxvdF9ncm91cCA8LSBwbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyfQojIGdldCBzYW1wbGUgc2l6ZXMgKGZvciB1c2UgaW4gcGxvdHMpCm5zIDwtIG1wX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY2xhZGUsIHNwZWNpZXMpICU+JQogIG11dGF0ZShuID0gbl9kaXN0aW5jdChzdWJqZWN0X3NpdGUpKSAlPiUKICBncm91cF9ieShjbGFkZSwgc3BlY2llcywgc2l0ZSwgbikgJT4lCiAgc3VtbWFyaXNlKG5fYnlfc2l0ZSA9IG5fZGlzdGluY3Qoc3ViamVjdF9zaXRlKSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NC41fQpwMiArIGFlcyh4ID0gZGVsYXksIHkgPSBjb3JyZWN0LCBjb2wgPSBkZWxheSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBwbG90X2luZGl2aWR1YWwsIGFlcyhzaXplID0gbnJfdHJpYWxzKSwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMTUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4pLCBzaGFwZSA9IDEsIHNpemUgPSAzLCBzdHJva2UgPSAxLjUpICsKICBnZW9tX2xpbmVyYW5nZShkYXRhID0gcGxvdF9ncm91cCwgYWVzKHkgPSBOVUxMLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIGx3ZCA9IDEuMikgKwogICMgZ2VvbV90ZXh0KGRhdGEgPSBucywgYWVzKGxhYmVsID0gbiksIHkgPSAtLjA1LCB4ID0gMiwgY29sID0gImJsYWNrIiwgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKHNwZWNpZXMgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODAsIGhqdXN0ID0gMCkpICsKICBzY2FsZV9zaXplX2FyZWEoIk51bWJlciBvZiBUcmlhbHMiLCBtYXhfc2l6ZSA9IDMsIGJyZWFrcyA9IGMoMTIsIDI0LCAzNikpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCJEZWxheSIsIGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBjb29yZF9mbGlwKHlsaW0gPSAwOjEpCmBgYAoKYGBge3J9Cmdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzAxX292ZXJ2aWV3LnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNC41LCBzY2FsZSA9IDIpCmdnc2F2ZSgiLi4vZ3JhcGhzL0ZpZzIudGlmZiIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gNC41LCBzY2FsZSA9IDIsIHR5cGUgPSAiY2Fpcm8iLCBjb21wcmVzc2lvbiA9ICJsenciKQpgYGAKCiMgT3ZlcnZpZXcgYnkgc3BlY2llcyBhY3Jvc3MgZGVsYXlzCgpgYGB7ciBvdmVydmlldyBieSBzcGVjaWVzIGFjcm9zcyBkZWxheXMsIHdhcm5pbmc9RkFMU0V9CnBsb3RfaW5kaXZpZHVhbDIgPC0gcGxvdF9pbmRpdmlkdWFsICU+JQogIGdyb3VwX2J5KGNsYWRlLCBzcGVjaWVzLCBzdWJqZWN0X3NpdGUpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkKCnBsb3RfZ3JvdXAyIDwtIHBsb3RfaW5kaXZpZHVhbDIgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjh9CnAxICsgYWVzKHggPSBmY3RfcmV2KHNwZWNpZXMpLCB5ID0gY29ycmVjdCwgY29sID0gY2xhZGUpICsKICBnZW9tX2ppdHRlcihkYXRhID0gcGxvdF9pbmRpdmlkdWFsMiwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMTUsIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcGxvdF9ncm91cDIsIGFlcyh5ID0gbWVhbiksIHNoYXBlID0gMSwgc2l6ZSA9IDMsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fbGluZXJhbmdlKGRhdGEgPSBwbG90X2dyb3VwMiwgYWVzKHkgPSBOVUxMLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIGx3ZCA9IDEuMikgKwogIGdlb21fdGV4dChkYXRhID0gbnMsIGFlcyhsYWJlbCA9IG4pLCB5ID0gLS4wNSwgY29sID0gImJsYWNrIiwgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKGNsYWRlIH4gLiwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wMl9vdmVydmlld19hY3Jvc3NfZGVsYXlzLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS44LCBzY2FsZSA9IDIpCmBgYAoKIyBQbG90cyBieSBzaXRlCgpIZXJlIHdlIHNlbGVjdCB0aGUgc3BlY2llcyBmb3Igd2hpY2ggd2UgaGF2ZSBkYXRhIGZyb20gbXVsdGlwbGUgc2l0ZXMuIFRoaXMgaXMgYSB2ZXJ5IHByZWxpbWluYXJ5IHdheSBvZiBjaGVja2luZyB3aGV0aGVyIHRoZXJlIGlzIGEgbG90IG9mIHZhcmlhdGlvbiBiZXR3ZWVuIHNpdGVzLiBQbG90dGluZyBjb252ZW50aW9ucyBhcmUgdGhlIHNhbWUgYXMgYWJvdmUuCgpGaXJzdCB3ZSBjaGVjayBmb3Igd2hpY2ggc3BlY2llcyB3ZSBoYXZlIGRhdGEgZnJvbSBtb3JlIHRoYW4gb25lIHNpdGU6CgpgYGB7ciBwbG90cyBieSBzaXRlLCByZXN1bHRzPSJhc2lzIn0KbXBfZGF0YSAlPiUKICBncm91cF9ieShzcGVjaWVzKSAlPiUKICBzdW1tYXJpc2Uoc2l0ZXMgPSBuX2Rpc3RpbmN0KHNpdGUpKSAlPiUKICBhcnJhbmdlKGRlc2Moc2l0ZXMpKSAlPiUKICBrbml0cjo6a2FibGUoKQpgYGAKCiMjIENoaW1wYW56ZWVzCgpgYGB7cn0KY2hpbXBfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkNoaW1wYW56ZWUiKSAlPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpjaGltcF9wbG90X2dyb3VwIDwtIGNoaW1wX3Bsb3RfaW5kaXZpZHVhbCAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTIuNX0KcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCwgY29sID0gZGVsYXkpICsKICBnZW9tX2ppdHRlcihkYXRhID0gY2hpbXBfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gY2hpbXBfcGxvdF9ncm91cCwgYWVzKHkgPSBtZWFuLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIHNpemUgPSAuOCwgc2hhcGUgPSAxLCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihucywgc3BlY2llcyA9PSAiQ2hpbXBhbnplZSIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZChzaXRlIH4gLiwgc3dpdGNoID0gInkiKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygic2hvcnQiLCAibWVkaXVtIiwgImxvbmciKSkgKwogIGdndGl0bGUoIkNoaW1wYW56ZWVzIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQojIGdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzAzX2NoaW1wX2J5X3NpdGUucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjUsIHNjYWxlID0gMiwgdHlwZSA9ICJjYWlybyIsIGNvbXByZXNzaW9uID0gImx6dyIpCmdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzAzX2NoaW1wX2J5X3NpdGUucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjUsIHNjYWxlID0gMikKYGBgCgoKIyMgUmluZy10YWlsZWQgbGVtdXJzCgpgYGB7cn0KcnRsZW11cl9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiUmluZy10YWlsZWQgbGVtdXIiKSAlPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpydGxlbXVyX3Bsb3RfZ3JvdXAgPC0gcnRsZW11cl9wbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjJ9CnAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QsIGNvbCA9IGRlbGF5KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IHJ0bGVtdXJfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gcnRsZW11cl9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICJSaW5nLXRhaWxlZCBsZW11ciIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZChzaXRlIH4gLiwgc3dpdGNoID0gInkiKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygic2hvcnQiLCAibWVkaXVtIiwgImxvbmciKSkgKwogIGdndGl0bGUoIlJpbmctdGFpbGVkIGxlbXVycyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMDRfcnRsZW11cl9ieV9zaXRlLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKCiMjIEJyb3duIENhcHVjaGlucwoKYGBge3J9CmNhcF9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQnJvd24gY2FwdWNoaW4gbW9ua2V5IikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKY2FwX3Bsb3RfZ3JvdXAgPC0gY2FwX3Bsb3RfaW5kaXZpZHVhbCAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuMn0KcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCwgY29sID0gZGVsYXkpICsKICBnZW9tX2ppdHRlcihkYXRhID0gY2FwX3Bsb3RfaW5kaXZpZHVhbCwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMywgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YSA9IGNhcF9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICJCcm93biBjYXB1Y2hpbiBtb25rZXkiKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBnZ3RpdGxlKCJDYXB1Y2hpbiBNb25rZXlzIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wNV9jYXB1Y2hpbl9ieV9zaXRlLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKIyMgQm9ub2JvcwoKYGBge3J9CmJvbl9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQm9ub2JvIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKYm9uX3Bsb3RfZ3JvdXAgPC0gYm9uX3Bsb3RfaW5kaXZpZHVhbCAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuMn0KcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCwgY29sID0gZGVsYXkpICsKICBnZW9tX2ppdHRlcihkYXRhID0gYm9uX3Bsb3RfaW5kaXZpZHVhbCwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMywgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YSA9IGJvbl9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICJCb25vYm8iKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBnZ3RpdGxlKCJCb25vYm9zIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wNl9ib25vYm9fYnlfc2l0ZS5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDEuMiwgc2NhbGUgPSAyKQpgYGAKCiMjIEdvcmlsbGEKCmBgYHtyfQpnb3JfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkdvcmlsbGEiKSAlPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpnb3JfcGxvdF9ncm91cCA8LSBnb3JfcGxvdF9pbmRpdmlkdWFsICU+JQogICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwMiArIGFlcyh4ID0gZGVsYXksIHkgPSBjb3JyZWN0LCBjb2wgPSBkZWxheSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBnb3JfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gZ29yX3Bsb3RfZ3JvdXAsIGFlcyh5ID0gbWVhbiwgeW1pbiA9IGNpX2xvd2VyLCB5bWF4ID0gY2lfdXBwZXIpLCBzaXplID0gLjgsIHNoYXBlID0gMSwgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIobnMsIHNwZWNpZXMgPT0gIkdvcmlsbGEiKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBnZ3RpdGxlKCJHb3JpbGxhcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMDdfZ29yaWxsYV9ieV9zaXRlLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKIyBUYXNrLWV4cGVyaWVuY2UKCkhlcmUgd2Ugc3BsaXQgZWFjaCBzcGVjaWVzIGJ5IHRhc2sgZXhwZXJpZW5jZS4gQ2hlY2sgaWYgd2UgaGF2ZSBzcGVjaWVzIHdpdGggc3VmZmljaWVudCBtZW1lYmVycyBoYXZpbmcgZGlmZmVyZW50IGxldmVscyBvZiB0YXNrIGV4cGVyaWVuY2UuCgpgYGB7ciBwbG90cyBieSB0YXNrIGV4cGVyaWVuY2UsIHJlc3VsdHM9ImFzaXMifQptcF9kYXRhICU+JQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIG11dGF0ZShsdmxzX3Rhc2tfZXhwID0gbl9kaXN0aW5jdCh0YXNrX2V4cGVyaWVuY2UpKSAlPiUKICBmaWx0ZXIobHZsc190YXNrX2V4cCA+IDEpICU+JQogIGdyb3VwX2J5KHNwZWNpZXMsIHRhc2tfZXhwZXJpZW5jZSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuX2Rpc3RpbmN0KHN1YmplY3Rfc2l0ZSkpICU+JQogIGtuaXRyOjprYWJsZSgpCmBgYAoKYGBge3J9CiMgZ2V0IHNhbXBsZSBzaXplcyAoZm9yIHVzZSBpbiBwbG90cykKbnNfdGFza19leHAgPC0gbXBfZGF0YSAlPiUKICBncm91cF9ieShjbGFkZSwgc3BlY2llcykgJT4lCiAgbXV0YXRlKG4gPSBuX2Rpc3RpbmN0KHRhc2tfZXhwZXJpZW5jZSkpICU+JQogIGdyb3VwX2J5KGNsYWRlLCBzcGVjaWVzLCB0YXNrX2V4cGVyaWVuY2UsIG4pICU+JQogIHN1bW1hcmlzZShuX2J5X3NpdGUgPSBuX2Rpc3RpbmN0KHN1YmplY3Rfc2l0ZSkpCmBgYAoKU28gZmFyLCB0aGlzIG9ubHkgYXBwbGllcyB0byBjaGltcHMgYW5kIGJvbm9ib3MuIEhvd2V2ZXIsIHRhc2sgZXhwZXJpZW5jZSBjby12YXJpZXMgd2l0aCBzaXRlLgoKPCEtLSAjIyBDaGltcGFuemVlcyAtLT4KCmBgYHtyfQpjaGltcF90YXNrX3Bsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJDaGltcGFuemVlIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgdGFza19leHBlcmllbmNlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpjaGltcF90YXNrX3Bsb3RfZ3JvdXAgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQ2hpbXBhbnplZSIpICU+JQogIGdyb3VwX2J5KHRhc2tfZXhwZXJpZW5jZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKSAlPiUKICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwX3Rhc2tleHBfY2hpbXAgPC0gcDIgKyBhZXMoeCA9IGRlbGF5LCB5ID0gY29ycmVjdCkgKwogIGdlb21faml0dGVyKGRhdGEgPSBjaGltcF90YXNrX3Bsb3RfaW5kaXZpZHVhbCwgYWVzKGNvbCA9IHNpdGUpLCB3aWR0aCA9IC4zLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC41LCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gY2hpbXBfdGFza19wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyLCBzaGFwZSA9IGRlbGF5KSwgc2l6ZSA9IC44LCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihuc190YXNrX2V4cCwgc3BlY2llcyA9PSAiQ2hpbXBhbnplZSIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZCh0YXNrX2V4cGVyaWVuY2UgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShsZWdlbmQuYm94ID0gImhvcml6b250YWwiLCBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODApKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgMiwgNSksIGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCkgKwogIGdndGl0bGUoIkNoaW1wYW56ZWVzIikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCjwhLS0gIyMgQm9ub2JvcyAtLT4KCmBgYHtyfQpib25vYm9fdGFza19wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiQm9ub2JvIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgdGFza19leHBlcmllbmNlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpib25vYm9fdGFza19wbG90X2dyb3VwIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkJvbm9ibyIpICU+JQogIGdyb3VwX2J5KHRhc2tfZXhwZXJpZW5jZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKSAlPiUKICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwX3Rhc2tleHBfYm9uIDwtIHAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QpICsKICBnZW9tX2ppdHRlcihkYXRhID0gYm9ub2JvX3Rhc2tfcGxvdF9pbmRpdmlkdWFsLCBhZXMoY29sID0gc2l0ZSksIHdpZHRoID0gLjMsIGhlaWdodCA9IC4wMTUsIGFscGhhID0gLjUsIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludHJhbmdlKGRhdGEgPSBib25vYm9fdGFza19wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyLCBzaGFwZSA9IGRlbGF5KSwgc2l6ZSA9IC44LCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihuc190YXNrX2V4cCwgc3BlY2llcyA9PSAiQmJvbm9ibyIpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZCh0YXNrX2V4cGVyaWVuY2UgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShsZWdlbmQuYm94ID0gImhvcml6b250YWwiLCBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODApKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgMiwgNSksIGJyZWFrcyA9IGMoInNob3J0IiwgIm1lZGl1bSIsICJsb25nIikpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKCkgKwogIGdndGl0bGUoIkJvbm9ib3MiKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTN9CmdyaWQuYXJyYW5nZShwX3Rhc2tleHBfY2hpbXAsIHBfdGFza2V4cF9ib24sIG5jb2wgPSAxKQpgYGAKCmBgYHtyfQpncm9iIDwtIGFycmFuZ2VHcm9iKHBfdGFza2V4cF9jaGltcCwgcF90YXNrZXhwX2JvbiwgbmNvbCA9IDEpCmdnc2F2ZSgiLi4vZ3JhcGhzLzAyXzA4X3Rhc2tfZXhwZXJpZW5jZS5wbmciLCBncm9iLCB3aWR0aCA9IDQsIGhlaWdodCA9IDMsIHNjYWxlID0gMikKYGBgCgoKIyBBZ2UKCkhlcmUgd2UgcGxvdCBhZ2UgYWdhaW5zdCBjb3JyZWN0IGNob2ljZSBzZXBhcmF0ZSBmb3IgZWFjaCBkZWxheSBhbmQgc3BlY2llcy4gUmVncmVzc2lvbiBsaW5lIGlzIHNtb290aGVkIGRlbGF5YWwgbWVhbi4KCmBgYHtyfQpwbG90X2FnZSA8LSBtcF9kYXRhICU+JQogIG11dGF0ZShkZWxheSA9IGZjdF9yZXYoZGVsYXkpKSAlPiUKICBncm91cF9ieShzdWJqZWN0X3NpdGUsIG5vcm1fYWdlLCBjbGFkZSwgc3BlY2llcywgZGVsYXkpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4zfQpnZ3Bsb3QocGxvdF9hZ2UsIGFlcyh4ID0gbm9ybV9hZ2UsIHkgPSBjb3JyZWN0KSkgKwogIGdlb21faml0dGVyKGFlcyhjb2wgPSBjbGFkZSksIHdpZHRoID0gLjA1LCBoZWlnaHQgPSAuMDUsIGFscGhhID0gLjUsIHNpemUgPSAyLjUpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAiYmxhY2siKSArCiAgIyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsdHkgPSAyKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS8zLCBsdHkgPSAyKSArCiAgZmFjZXRfZ3JpZCh+IGRlbGF5KSArCiAgbGFicyh4ID0gIk5vcm1lZCBBZ2UgKHJlbGF0aXZlIHRvIHNwZWNpZXMgbG9uZ2V2aXR5KSIsIHkgPSAiUHJvcG9ydGlvbiBDb3JyZWN0IikgKwogIHNjYWxlX2NvbG9yX3NvbGFyaXplZCgiQ2xhZGUiKSArCiAgeWxpbShjKC0uMDUsIDEuMDUpKQpgYGAKCmBgYHtyfQpnZ3NhdmUoIi4uL2dyYXBocy8wMl8wOV9hZ2VfYnlfZGVsYXkucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAxLjMsIHNjYWxlID0gMikKZ2dzYXZlKCIuLi9ncmFwaHMvRmlnNC50aWZmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAxLjMsIHNjYWxlID0gMiwgdHlwZSA9ICJjYWlybyIsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNH0KZ2dwbG90KHBsb3RfYWdlLCBhZXMoeCA9IG5vcm1fYWdlLCB5ID0gY29ycmVjdCkpICsKICBnZW9tX2ppdHRlcihhZXMoZmlsbCA9IHNwZWNpZXMpLCB3aWR0aCA9IC4wNSwgaGVpZ2h0ID0gLjA1LCBhbHBoYSA9IC41LCBzaXplID0gMi41LCBzaGFwZSA9IDIxLCBzdHJva2UgPSAwKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbCA9IGRlbGF5KSwgbWV0aG9kID0gImxtIiwgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEvMywgbHR5ID0gMikgKwogIGZhY2V0X2dyaWQoZGVsYXkgfiBjbGFkZSwgc2NhbGVzID0gImZyZWVfeCIpICsKICBsYWJzKHggPSAiTm9ybWVkIEFnZSAocmVsYXRpdmUgdG8gc3BlY2llcyBsb25nZXZpdHkpIiwgeSA9ICJQcm9wb3J0aW9uIENvcnJlY3QiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KHNvbGFyaXplZF9wYWxldHRlKDMpKSkgKwogIHlsaW0oYygtLjA1LCAxLjA1KSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMTBfYWdlX2J5X2RlbGF5X3NwZWNpZXMucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjQsIHNjYWxlID0gMikKYGBgCgoKIyBDdXAgZGlzdGFuY2UKCihzaWcuIGVmZmVjdCBpbiBwcmVsaW1pbmFyeSBtb2RlbCkKCmBgYHtyfQpwbG90X2N1cCA8LSBtcF9kYXRhICU+JQogICBncm91cF9ieShzdWJqZWN0X3NpdGUsIGN1cF9kaXN0YW5jZSwgY2xhZGUsIHNwZWNpZXMsIGRlbGF5KSAlPiUKICAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQpgYGAKCmBgYHtyIHBsb3R0aW5nIGN1cCBkaXN0YW5jZSwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9Mn0KY3AgPC0gZ2dwbG90KHBsb3RfY3VwLCBhZXMoeCA9IGN1cF9kaXN0YW5jZSwgeSA9IGNvcnJlY3QpKSArCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbCA9IGNsYWRlKSwgd2lkdGggPSAuNSwgaGVpZ2h0ID0gLjE1LCBhbHBoYSA9IC41LCBzaXplID0gMikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJibGFjayIpICsKICBsYWJzKHggPSAiQ3VwIERpc3RhbmNlIGluIGNtIiwgeSA9ICJQcm9wb3J0aW9uIENvcnJlY3QiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS8zLCBsdHkgPSAyKSArCiAgc2NhbGVfY29sb3Jfc29sYXJpemVkKCJDbGFkZSIpICsKICB5bGltKGMoLS4wNSwgMS4wNSkpCgpjcCArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKC41LCA1LCAuNSwgLjUpLCAiY20iKSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCIuLi9ncmFwaHMvMDJfMTFfY3VwX2Rpc3RhbmNlLnBuZyIsIGNwLCB3aWR0aCA9IDMsIGhlaWdodCA9IDIsIHNjYWxlID0gMikKYGBgCgo=